package com.example.springboot.aop;

import com.example.springboot.annotation.RateLimiting;
import com.example.springboot.manager.RedisLimiterManager;
import com.example.springboot.pojo.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import static com.example.springboot.contant.UserConstant.USER_LOGIN_STATE;

/**
 * 限流切面
 * @Author: ysx
 */
@Aspect
@Component
@Slf4j
public class RateLimitingAspect {

    @Resource
    private RedisLimiterManager redisLimiterManager;

    /**
     * 切入点
     * @Pointcut注解表示切入点的表达式有多种，最常用的是两种，execution表达式和@annotation注解；
     * execution(* com.example.springboot.mapper.*.*(..)) 表示 com.sky.mapper包下所有类的所有方法
     * @annotation(com.example.springboot.annotation.AutoFill) 表示 com.sky.annotion包下的AutoFill注解
     */
    @Pointcut("execution(* com.example.springboot.service.*.*(..)) && @annotation(com.example.springboot.annotation.RateLimiting)")
    public void rateLimitingPointCut(){}

    /**
     * 前置通知，在通知中进行公共字段赋值
     * 可以joinpoint中得到命中方法的相关信息，利用这些信息可以做一些额外的业务操作；
     * @Before("rateLimitingPointCut()") rateLimitingPointCut()的切入点
     */
    @Before("rateLimitingPointCut()")
    public void rateLimiting(JoinPoint joinPoint){
        log.info("开始限流...");
        //获取到当前被拦截的方法上的数据库操作类型
        MethodSignature signature=(MethodSignature) joinPoint.getSignature();//对象方法签名
        RateLimiting rateLimiting = signature.getMethod().getAnnotation(RateLimiting.class);//获得方法上的注解对象
        String key = rateLimiting.key();//获得数据库操作对象
        //获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser=(User) userObj;
        redisLimiterManager.doRateLimit(key+currentUser.getId());

    }
}
